extends IBasicComponent


class_name RemoteResourceLoader
"""
远端资源加载器,如果本地没有资源则从服务器下载
"""


## 下载进度
signal event_download_progress(loader: RemoteResourceLoader, total_count: int, left_count: int)
## 任务全部完成
signal event_download_completed(loader: RemoteResourceLoader)


## 是否使用本地已下载的资源
@export var is_using_cache: bool = true
## 缓存位置
@export var cache_prefix: String = "user://"
## 下载器
@export var http_resource_loader: HttpResourceLoader = null


var download_total_count: int = 0
var download_left_count: int = 0


func __check_exports() -> Dictionary:
    return IComponent.merge({
        "http_resource_loader": IComponent.find_down.bind(self, func(x): return x is HttpResourceLoader, http_resource_loader),
    }, super.__check_exports())

func __on_download_left_update(increment: int) -> void:
    if increment != 0:
        download_left_count += increment
        if increment > 0:
            download_total_count += increment
        event_download_progress.emit(self, download_total_count, download_left_count)
    check_completed()

func check_completed() -> void:
    if download_left_count < 1:
        download_total_count = 0
        event_download_completed.emit(self)

func __on_download_completed(body: PackedByteArray, url: String, on_download_success: Callable) -> void:
    if is_using_cache:
        __save_to_cache(url, body)

    on_download_success.call(body, null)
    __on_download_left_update(-1)

func is_http_url(url: String) -> bool:
    return url.begins_with("http://")

func get_local_url(url: String) -> String:
    var sub_url = url.substr(url.find("//") + 2)
    return cache_prefix + sub_url.substr(sub_url.find('/') + 1)

func get_cached_url(url: String) -> String:
    if not is_http_url(url):
        return url
    var local_url = get_local_url(url)
    if FileAccess.file_exists(local_url):
        return local_url
    return url

func __save_to_cache(url: String, body: PackedByteArray) -> String:
    var local_url = get_local_url(url)
    # check dir
    DirAccess.make_dir_recursive_absolute(local_url.substr(0, local_url.rfind('/')))
    # store file
    var file = FileAccess.open(local_url, FileAccess.WRITE)
    file.store_buffer(body)
    file.close()
    return local_url

func load_from(url: String, on_download_success: Callable) -> void:
    var cached_url = get_cached_url(url) if is_using_cache else url
    if is_http_url(cached_url):
        __on_download_left_update(1)
        http_resource_loader.download(cached_url, __on_download_completed.bind(cached_url, on_download_success))
    elif cache_prefix.begins_with("user://"):
        on_download_success.call(FileAccess.get_file_as_bytes(cached_url), null)
    elif cached_url.begins_with("res://"):
        on_download_success.call(PackedByteArray(), load(cached_url))
    else:
        # 本地目录
        on_download_success.call(FileAccess.get_file_as_bytes(cached_url), null)
